#!/usr/bin/python
import wx
from math import *
import os
import sys
import serial
from string import *
import re
import imp
WINDOW_X = 800
WINDOW_Y = 400
CFG_DIR = "./"
CFG_FILE = "test.py"

WRITE_CTRL_DIR = "./CTRL_MOT/"
#WRITE_CTRL_FILE = "7144_45_F492_P384.MOT"
WRITE_CTRL_FILE = "7144_45_F50M_P384.MOT"
#WRITE_CTRL = "7144_45_F50M_P384"
PROG_DIR = "./PROG/"
PROG_FILE = "TERA4.mot"
#PROG_FILE = "Led2nd.mot"
PORT = '/dev/ttyUSB0'
BAUDRATE_B  = 19200
#BAUDRATE_B  = 38400
BAUDRATE_P  = 38400
VERIFY = 1

BAUDRATE_LIST = ["--Select Baudrate--","1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"]
BAUD_CH = chr(0x00)	#NULL
BAUD_CH_OK = chr(0x55)	#U
BAUD_CH_DONE = chr(0xAA)	#U
BAUD_CH_LIMIT = 30

PDATA = []
WCDATA = []
PROG_DATA = []
DATA_ERR = chr(0xFF)
UL_OK = chr(0xAA)
ROM_START = 0
ROM_END = 0x3ffff
BLOCK_SIZE = 128
BLANK_DATA = chr(0xFF)

#Program write
PROG_START = chr(0x55)	#U
PROG_OK = chr(0xAA)	#U
VER_START = chr(0x56)

class PROG_DATA:
	def __init__(self, addr, size ,data):
		self.addr = addr
		self.size = size
		self.data = data
class BALK_DATA:
	def __init__(self, addr,data):
		self.addr = addr
		self.data = data
#Window
class MainFrame(wx.Frame):
	def __init__(self, parent, id, title):
		global WINDOW_X, WINDOW_Y
		wx.Frame.__init__(self, parent, id, title, size=(WINDOW_X, WINDOW_Y))
		# Setting up the menu.
		filemenu= wx.Menu()
		#menuOpen = filemenu.Append(wx.ID_OPEN,"&Open"," Open files")
		menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
		#setupmenu =  wx.Menu()
		#menuMachine = setupmenu.Append(wx.ID_SETUP,"&Machine setup"," Setup Machine")
		#menuConv = setupmenu.Append(wx.ID_VIEW_LIST,"&Convert setup"," Convert setup")
		# Creating the menubar.
		menuBar = wx.MenuBar()
		menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
		#menuBar.Append(setupmenu,"&Setup") # Adding the "filemenu" to the MenuBar
		self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.

		#Event for Menu bar
		#self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
		self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
		panel = wx.Panel(self, -1)
		sizer = wx.GridBagSizer(0, 0)
		#Write contrl
		write_ctrl_txt = wx.StaticText(panel, -1, "Write Control Program:")
		sizer.Add(write_ctrl_txt, (0, 0), flag=wx.TOP | wx.LEFT, border=10)

		self.wcfs = get_mot_list(WRITE_CTRL_DIR)
		self.wcfs.insert(0,"--Select Write Control Program File--")
		selected_wcf = 0
		for i, v in enumerate(self.wcfs):
			if(str(v) == str(WRITE_CTRL_FILE)):
				selected_wcf = i
				break
		self.wcf = wx.ComboBox(panel, -1, pos=(50, 170), size=(150, -1), choices=self.wcfs, 
					style=wx.CB_READONLY)
		self.wcf.SetSelection(int(selected_wcf))
		sizer.Add(self.wcf, (0, 1), (1, 4), wx.TOP | wx.EXPAND, 5)

		#Baudrate 4 Write Control Program
		baud_wc_txt = wx.StaticText(panel, -1, "Baud rate for Write Control:")
		sizer.Add(baud_wc_txt, (1, 0), flag=wx.TOP | wx.LEFT, border=10)

		#self.wcfs = get_mot_list(WRITE_CTRL_DIR)
		selected_baud_wc = 0
		for i, v in enumerate(BAUDRATE_LIST):
			if(str(v) == str(BAUDRATE_B)):
				selected_baud_wc = i
				break
		self.bwc = wx.ComboBox(panel, -1, pos=(50, 170), size=(150, -1), choices=BAUDRATE_LIST, 
					style=wx.CB_READONLY)
		self.bwc.SetSelection(int(selected_baud_wc))
		sizer.Add(self.bwc, (1, 1), (1, 3), wx.TOP | wx.EXPAND, 5)

		#Baudrate 4 Write Control Program
		baud_pr_txt = wx.StaticText(panel, -1, "Baud rate for Program:")
		sizer.Add(baud_pr_txt, (2, 0), flag=wx.TOP | wx.LEFT, border=10)

		selected_baud_pr = 0
		for i, v in enumerate(BAUDRATE_LIST):
			if(str(v) == str(BAUDRATE_P)):
				selected_baud_pr = i
				break
		self.bpr = wx.ComboBox(panel, -1, pos=(50, 170), size=(150, -1), choices=BAUDRATE_LIST, 
					style=wx.CB_READONLY)
		self.bpr.SetSelection(int(selected_baud_pr))
		sizer.Add(self.bpr, (2, 1), (1, 3), wx.TOP | wx.EXPAND, 5)

		#Prgram
		pr_txt = wx.StaticText(panel, -1, "Program:")
		sizer.Add(pr_txt, (3, 0), flag=wx.TOP | wx.LEFT, border=10)

		self.prs = get_mot_list(PROG_DIR)
		self.prs.insert(0,"--Select Program File--")
		selected_pr = 0
		for i, v in enumerate(self.prs):
			if(str(v) == str(PROG_FILE)):
				selected_pr = i
				break
		self.pr = wx.ComboBox(panel, -1, pos=(50, 170), size=(150, -1), choices=self.prs, 
					style=wx.CB_READONLY)
		self.pr.SetSelection(int(selected_pr))
		sizer.Add(self.pr, (3, 1), (1, 4), wx.TOP | wx.EXPAND, 5)
		#Port
		port_txt = wx.StaticText(panel, -1, "Serial Port:")
		sizer.Add(port_txt, (4, 0), flag=wx.TOP | wx.LEFT, border=10)

		self.ports = get_port_list()
		self.ports.insert(0,"--Select Port--")
		selected_ports = 0
		for i, v in enumerate(self.ports):
			if(str(v) == str(PORT)):
				selected_ports = i
				break
		self.port = wx.ComboBox(panel, -1, pos=(50, 170), size=(150, -1), choices=self.ports, 
					style=wx.CB_READONLY)
		self.port.SetSelection(int(selected_ports))
		sizer.Add(self.port, (4, 1), (1, 3), wx.TOP | wx.EXPAND, 5)
		#Button
		write_button = wx.Button(panel, -1, "Write", size=(-1, 30))
		sizer.Add(write_button, (5, 3), (1, 1),  wx.LEFT, 10)
		panel.SetSizer(sizer)
		sizer.Fit(self)
		self.Centre()
		self.Show(True)

		# Events.
		self.Bind(wx.EVT_BUTTON, self.OnWrite, write_button)

	#functions
	def OnWrite(self,e):
		global WRITE_CTRL_FILE,PROG_FILE,BAUDRATE_B,BAUDRATE_P,PORT
		if(self.wcf.GetSelection()):
			print "WC"
			WRITE_CTRL_FILE = self.wcfs[int(self.wcf.GetSelection())]
		if(self.pr.GetSelection()):
			print "PROG"
			PROG_FILE = self.prs[int(self.pr.GetSelection())]
		if(self.bwc.GetSelection() >= 0):
			BAUDRATE_B = int(BAUDRATE_LIST[int(self.bwc.GetSelection())])
		if(self.bpr.GetSelection() >= 0):
			BAUDRATE_P = int(BAUDRATE_LIST[int(self.bpr.GetSelection())])
		if(self.port.GetSelection() >= 0):
			PORT = self.ports[int(self.port.GetSelection())]
		#print WRITE_CTRL_FILE,PROG_FILE,BAUDRATE_B,BAUDRATE_P,PORT
		#Write
		up_write_ctrl()
		#
		up_prog()
		dlg = wx.MessageDialog(self, "Program writing is finished", "Program writing is finished" , wx.OK)
		dlg.ShowModal() # Shows it
		dlg.Destroy()
		#self.Close(True)  # Close the frame.
	def OnExit(self,e):
		self.Close(True)  # Close the frame.
	def OnOpen(self,e):
		setup = OpenFiles(None, -1, 'Open Files')
		setup.ShowModal()
		setup.Destroy()
		self.Refresh(1)
def main():
	app = wx.App()
	MainFrame(None, -1, 'wxSH8Writer')
	app.MainLoop()
def up_write_ctrl():
	total_size = parse_mot(WRITE_CTRL_DIR,WRITE_CTRL_FILE)
	WCDATA = PDATA
	#print "total data size =",total_size
	low = total_size[-2:]
	hi = total_size[2:-2]
	#print hi,low
	hi_addr = chr(int(hi,16))
	low_addr = chr(int(low,16))
	ser = serial.Serial(
		port = PORT,
		baudrate = int(BAUDRATE_B),
		parity = serial.PARITY_NONE,
		bytesize = serial.EIGHTBITS,
		stopbits = serial.STOPBITS_ONE,
		timeout = 1, ## Sec
	)
	#Open serial port
	ser.open()
	i = 0
	print "Synchronize Baudrate"
	while(1):
		#Send Data
		#print "Sync Baudrate"
		ser.write(BAUD_CH)
		#Read responce
		ret = ser.read(size=1)
		if ret == BAUD_CH:
			print "Synchronized !"
			break
		if i >= BAUD_CH_LIMIT:
			print "Error:No response"
			exit()
		i += 1
	#SEND OK
	ser.write(BAUD_CH_OK)
	ret = ser.read(size=1)
	if ret == BAUD_CH_DONE:
		print "Baudrate synchroniziton done!"

	### Write control program ###
	#Send addr hi
	ser.write(hi_addr)
	#Send addr low
	ser.write(low_addr)
	#Get echo back
	ret_hi = ser.read(size=1)
	ret_low = ser.read(size=1)
	if ret_hi != hi_addr:
		print "Error: hi addr"
	#else:
	#	print "hi addr confirmed"
	if ret_low != low_addr:
		print "Error : low addr"
	#else:
	#	print "low addr confirmed"
	#Send write control program
	print "Upload write control program :",WRITE_CTRL_FILE
	for prg_data in WCDATA:
		#print prg_data.data
		i = 0
		while i <= len(prg_data.data):
			byte_data = prg_data.data[i:i+2]
			if not byte_data:
				i+=2
				continue
			#print byte_data
			send_data = chr(int(byte_data,16))
			#send data
			ser.write(send_data)
			#Get echo back
			eb = ser.read(size=1)
			if eb == send_data:
				#print "data ok"
				i+=2
				continue
			elif eb == DATA_ERR:
				print "data error"
				exit()
			elif eb == UL_OK:
				print "Write control program was Uploaded?"
			i+=2
	#Get Upload done
	ul_d = ser.read(size=1)
	if ul_d == UL_OK:
		print "Write control program was Uploaded"
	else:
		print "Upload error"
		exit()
	#Close serial port
	ser.close()
def up_prog():
	PDATA = []
	pgtotal_size = parse_mot(PROG_DIR,PROG_FILE)
	#print "total data size =",pgtotal_size
	ch_prog()
	#ch_prog_test()
	#exit()
	#Set serial
	ser = serial.Serial(
		port = PORT,
		baudrate = int(BAUDRATE_P),
		parity = serial.PARITY_NONE,
		bytesize = serial.EIGHTBITS,
		stopbits = serial.STOPBITS_ONE,
		timeout = 1, ## Sec
	)
	#Open serial port
	ser.open()
	#print "data line =",len(PROG_DATA)
	print ""
	print "Write program :",PROG_FILE
	for bdata in PROG_DATA:
		if not bdata:
			continue
		tmp_addr = "000000" + hex(bdata.addr)[2:]
		tmp_addr = tmp_addr[-6:]
		low = tmp_addr[-2:]
		mid = tmp_addr[2:-2]
		hi = tmp_addr[:2]
		hi_addr = chr(int(hi,16))
		mid_addr =chr(int(mid,16))
		low_addr = chr(int(low,16))
		#Send program start
		ser.write(PROG_START)
		#send addr
		ser.write(low_addr)
		ser.write(mid_addr)
		ser.write(hi_addr)
		#send program
		#print "addr =",bdata.addr,", data size =",len(bdata.data)
		for send_data in bdata.data:	
			#if send_data == VER_START:
			#	print "verify?"
			ser.write(send_data)
		#print "last send data =",hex(ord(send_data))
		is_ok = ser.read(size=1)
		if is_ok != PROG_OK:
			tmp = ord(is_ok)
			tmp = hex(tmp)
			print "program write error",tmp
			print "last send data =",hex(ord(send_data))
			print "addr =",hex(bdata.addr),", data =",bdata.data
			exit()
		if VERIFY:
			#Verify start
			ser.write(VER_START)
			#send addr
			ser.write(low_addr)
			ser.write(mid_addr)
			ser.write(hi_addr)
			#read addr
			tmp_low = ser.read(size=1)
			tmp_mid = ser.read(size=1)
			tmp_hi = ser.read(size=1)
			for send_data in bdata.data:	
				#read Verify data
				ret = ser.read(size=1)
				if ret != send_data:
					print "Verify error : send data =",hex(ord(send_data)), ", recive data =",hex(ord(ret))
					print low,mid,hi
					print hex(ord(tmp_low)),hex(ord(tmp_mid)),hex(ord(tmp_hi))
			print "Verify OK"
	print "Writing program completed"
	#Close serial port
	ser.close()

def ch_prog():
	global PROG_DATA
	### Write Program ###
	prog_data = []
	PROG_DATA = []
	tmp_addr = PDATA[0].addr
	pre_size = PDATA[0].size
	pre_addr = PDATA[0].addr - pre_size

	for prg_data in PDATA:
		this_addr = pre_addr + pre_size
		if this_addr != prg_data.addr:
			#print "change addr: this =",this_addr, ", next =",prg_data.addr
			if len(prog_data) > 0 and len(prog_data) < BLOCK_SIZE:
				#print "Fill blank_data"
				sub = BLOCK_SIZE - len(prog_data)
				for j in range(sub):
					prog_data.append(BLANK_DATA)
				#print len(prog_data)
				PROG_DATA.append(BALK_DATA(tmp_addr,prog_data))
				prog_data = []
			tmp_addr = prg_data.addr
		i = 0
		while i <= len(prg_data.data):
			byte_data = prg_data.data[i:i+2]
			if not byte_data:
				i+=2
				continue
			hex_data = chr(int(byte_data,16))
			prog_data.append(hex_data)
			if len(prog_data) == BLOCK_SIZE:
				PROG_DATA.append(BALK_DATA(tmp_addr,prog_data))
				prog_data = []
				tmp_addr = prg_data.addr + int(i/2) + 1
			i += 2
		pre_addr = prg_data.addr
		pre_size = prg_data.size
	this_addr = pre_addr + pre_size
	if this_addr != prg_data.addr:
		if len(prog_data) > 0 and len(prog_data) < BLOCK_SIZE:
			sub = BLOCK_SIZE - len(prog_data)
			for j in range(sub):
				prog_data.append(BLANK_DATA)
			PROG_DATA.append(BALK_DATA(tmp_addr,prog_data))

def parse_mot(dirname, filename):
	global PDATA
	PDATA = []
	size = 4
	data_size = 0
	total_byte = 0
#http://www.exp.org/h8/ml/archive/cgi/view.cgi?message=392
	for data in read_mot_file(dirname, filename):
		#print data
		data.strip()
		if not data:
			continue
		if data[0] == 'S':
			byte_size=int(data[2:4], 16)
			#print data[2:4],"=",byte_size
			if data[1] == '0':	#Header
				#print "Header"
				#file name
				fname = data[8:]
				#print "Header =",fname
			elif data[1] == '1':	#4 data record
				size = 4
				addr = int(data[4:4 + size], 16)
				prg_data = data[4 + size:byte_size*2+2]
				ch_sum = data[byte_size*2+2:]
				data_size = byte_size - int(size/2) - 1
				total_byte += data_size
				PDATA.append(PROG_DATA(addr,data_size,prg_data))
			elif data[1] == '2':	#6 data record
				size = 6
				addr = int(data[4:4 + size], 16)
				prg_data = data[4 + size:byte_size*2+2]
				ch_sum = data[byte_size*2+2:]
				data_size = byte_size - int(size/2) - 1
				total_byte += data_size
				PDATA.append(PROG_DATA(addr,data_size,prg_data))
			elif data[1] == '3':	#8 data record
				size = 8
				addr = int(data[4:4 + size], 16)
				prg_data = data[4 + size:byte_size*2+2]
				ch_sum = data[byte_size*2+2:]
				data_size = byte_size - int(size/2) - 1
				total_byte += data_size
				#print "data =",prg_data,ch_sum,"total =",total_byte
				#print "total =",total_byte
				PDATA.append(PROG_DATA(addr,data_size,prg_data))
			#elif data[1] == '5':	#Special
			elif data[1] == '7':	#8 Start address
				size = 8
				start_addr = int(data[4:4 + size], 16)
			elif data[1] == '8':	#6 Start address
				size = 6
				start_addr = int(data[4:4 + size], 16)
			elif data[1] == '9':	#4 Start address
				size = 4
				start_addr = int(data[4:4 + size], 16)
			else:
				continue
			#print data[4:4 + size]
			#addr = int(data[4:4 + size], 16)
		else:
			continue

	print "MOT program was parsed :",filename
	total_size = hex(total_byte)
	return total_size
		
def read_mot_file(dirname, filename):
#def read_mot_file():
	file_name = os.path.join(dirname, filename)
	try:
		f = open(file_name,'r')
	except IOError, (errno, strerror):
		print "Unable to open the file" + file_name + "\n"
		return []
	else:
		all_lines = f.read()
		return all_lines.split("\n")
def read_cfg(cfg_file):
	global WRITE_CTRL_DIR, WRITE_CTRL_FILE, PROG_DIR, PROG_FILE, PORT, BAUDRATE_B, BAUDRATE_P
	if(cfg_file):
		ini = get_plugin(CFG_DIR,cfg_file)
	else:
		return
	try:
		WRITE_CTRL_DIR = str(ini.WRITE_CTRL_DIR)
	except AttributeError:
		print "No WRITE_CTRL_DIR data in config file. Set default value"
	try:
		WRITE_CTRL_FILE = str(ini.WRITE_CTRL_FILE)
	except AttributeError:
		print "No WRITE_CTRL_FILE data in config file. Set default value"
	try:
		PROG_DIR = str(ini.PROG_DIR)
	except AttributeError:
		print "No PROG_DIR data in config file. Set default value"
	try:
		PORT = str(ini.PORT)
	except AttributeError:
		print "No PORT data in config file. Set default value"
	try:
		BAUDRATE_B = int(ini.BAUDRATE_B)
	except AttributeError:
		print "No BAUDRATE_B data in config file. Set default value"
	try:
		BAUDRATE_P = int(ini.BAUDRATE_P)
	except AttributeError:
		print "No BAUDRATE_P data in config file. Set default value"
def get_port_list():
	os_name = os.name
	if(os_name == 'posix'):	#Unix
		port_list = []
		#return glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*')
		for port in os.listdir("/dev/"):
			if  port.startswith(("ttyS","ttyUSB")):
				#mot = fdn.replace(".MOT","")
				#mot_list.append(mot)
				port_list.append("/dev/" + port)
		return port_list
	else:
		return scan()

def scan():
    #"""scan for available ports. return a list of tuples (num, name)"""
    available = []
    for i in range(256):
        try:
            s = serial.Serial(i)
            available.append( (i, s.portstr))
            s.close()   # explicit close 'cause of delayed GC in java
        except serial.SerialException:
            pass
    return available
def get_mot_list(dir):
	mot_list = []
	for fdn in os.listdir(dir):
		if fdn.endswith((".MOT","mot")):
			#mot = fdn.replace(".MOT","")
			#mot_list.append(mot)
			mot_list.append(fdn)
	return mot_list
def get_plugin(dir,name):
	cwd = os.getcwd()
	moduledir = os.path.join(cwd,dir)
	plugin_name = name + ".py"
	plugin = load_plugin(moduledir,plugin_name)
	return plugin

def load_module(module_name,basepath):
	f,n,d = imp.find_module(module_name,[basepath])
	return imp.load_module(module_name,f,n,d)
def load_plugin(basepath,plugin_file):
	try:
		m = load_module(plugin_file.replace(".py",""),basepath)
		return m
	except ImportError:
		pass
	return
if __name__ == "__main__":
	main()
